package com.aiti.ai.service.impl;

import cn.hutool.core.util.StrUtil;
import com.aiti.ai.constant.PromptConstant;
import com.aiti.ai.dto.ai.ExistFieldDto;
import com.aiti.ai.dto.ai.NewFieldDto;
import com.aiti.ai.entity.AiEnterpriseEntity;
import com.aiti.ai.entity.AiProductEntity;
import com.aiti.ai.entity.BiddingProjectEntity;
import com.aiti.ai.entity.CategoryInfoEntity;
import com.aiti.ai.mapper.BiddingProjectMapper;
import com.aiti.ai.service.AiEnterpriseService;
import com.aiti.ai.service.AiProductService;
import com.aiti.ai.service.CategoryInfoService;
import com.aiti.ai.service.EnterpriseDealService;
import com.aiti.ai.service.ai.MessageAssistant;
import com.aiti.ai.tool.BochaAPITool;
import com.aiti.ai.tool.SearXNGWebSearchTool;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.service.AiServices;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

@Service
@Slf4j
public class EnterpriseDealServiceImpl implements EnterpriseDealService {
    @Autowired
    private ChatLanguageModel model;
    @Autowired
    private CategoryInfoService categoryInfoService;
    @Autowired
    private AiEnterpriseService aiEnterpriseService;
    @Autowired
    private AiProductService aiProductService;
    @Autowired
    private BiddingProjectMapper biddingProjectMapper;
    @Autowired
    private SearXNGWebSearchTool searXNGWebSearchTool;

    private final ExecutorService executorService = Executors.newFixedThreadPool(5);
    private final AtomicLong taskCounter = new AtomicLong(0);
    private final Object lock = new Object();
    private volatile boolean shutdownRequested = false;

    @Override
    public void dealEnterprise() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        LambdaQueryWrapper<AiEnterpriseEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.isNull(AiEnterpriseEntity::getAiDealFlag).orderByDesc(AiEnterpriseEntity::getBaseCreateTime);

        int pageSize = 10;
        int currentPage = 1;
        boolean hasMore = true;

        LambdaQueryWrapper<CategoryInfoEntity> categoryWrapper = new LambdaQueryWrapper<>();
        categoryWrapper.ne(CategoryInfoEntity::getParentCategoryId, "00");
        List<CategoryInfoEntity> categoryList = categoryInfoService.list(categoryWrapper);
        Map<String, String> categoryMap = categoryList.stream().collect(Collectors.toMap(CategoryInfoEntity::getCategoryName, CategoryInfoEntity::getCategoryPath, (existing, replacement) -> existing));
        Set<String> categorySet = categoryMap.keySet();
        String categoryNames = categorySet.stream().collect(Collectors.joining(StrUtil.COMMA));

        while (!shutdownRequested && hasMore) {
            Page<AiEnterpriseEntity> pageResult = aiEnterpriseService.page(new Page<>(currentPage, pageSize), queryWrapper);
            List<AiEnterpriseEntity> enterpriseList = pageResult.getRecords();

            if (enterpriseList.isEmpty()) {
                hasMore = false;
                break;
            }

            for (final AiEnterpriseEntity enterpriseEntity : enterpriseList) {
                if (shutdownRequested) {
                    break;
                }
                // 提交任务给线程池
                executorService.submit(() -> {
                    try {
                        processEnterpriseEntity(enterpriseEntity, formatter, categoryMap, categoryNames);
                    } catch (Exception e) {
                        log.error(e.getMessage());
                    } finally {
                        taskCounter.decrementAndGet();
                        synchronized (lock) {
                            lock.notifyAll();
                        }
                    }
                });
                taskCounter.incrementAndGet();
            }

            if (enterpriseList.size() < pageSize) {
                hasMore = false;
            }

            currentPage++;
        }


        synchronized (lock) {
            while (taskCounter.get() > 0 && !shutdownRequested) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }


        if (shutdownRequested) {
            shutdownExecutorService();
        }
    }

    @Override
    public void requestShutdown() {
        this.shutdownRequested = true;
        synchronized (lock) {
            lock.notifyAll();
        }
    }

    private void shutdownExecutorService() {
        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(1, TimeUnit.HOURS)) {
                executorService.shutdownNow();
            }
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
        }
    }

    private void processEnterpriseEntity(AiEnterpriseEntity enterpriseEntity, SimpleDateFormat formatter, Map<String, String> categoryMap, String categoryNames) throws Exception {
        String baseName = enterpriseEntity.getBaseName();
        String existFieldPrompt = String.format(PromptConstant.EXIST_FIELD_PROMPT, baseName);
        String newFieldPrompt = String.format(PromptConstant.NEW_FIELD_PROMPT, baseName);
//        ChatMessage chatMessage = new UserMessage(existFieldPrompt);
//        ChatResponse chat = model.chat(chatMessage);
//        AiMessage aiMessage = chat.aiMessage();
//        String text = aiMessage.text();
//        String existFieldJsonString = text.replace("```json", "").replace("```", "");


//        MessageAssistant assistant = AiServices.builder(MessageAssistant.class)
//                .chatLanguageModel(model)
//                .tools(bochaAPITool).build();
//        String existFieldJsonString = assistant.dealExistField(baseName);
//        existFieldJsonString = existFieldJsonString.replace("```json", "").replace("```", "");
//        log.info("生成旧字段返回结果:{}",existFieldJsonString);
//        AiEnterpriseEntity aiEnterpriseEntity = JSONObject.parseObject(existFieldJsonString, AiEnterpriseEntity.class);

        MessageAssistant assistant = AiServices.builder(MessageAssistant.class)
                .chatLanguageModel(model)
                .tools(searXNGWebSearchTool).build();
        ExistFieldDto existFieldDto = assistant.dealExistFieldNew(baseName);
        log.info("生成旧字段返回结果:{}",existFieldDto);
        AiEnterpriseEntity aiEnterpriseEntity = new AiEnterpriseEntity();
        BeanUtils.copyProperties(existFieldDto, aiEnterpriseEntity);

        Class<? extends AiEnterpriseEntity> aClass = populateValue(enterpriseEntity, aiEnterpriseEntity, null, true);

//        ChatMessage newFieldChatMessage = new UserMessage(newFieldPrompt);
//        ChatResponse newFieldChat = model.chat(newFieldChatMessage);
//        AiMessage newFieldAiMessage = newFieldChat.aiMessage();
//        String newFieldText = newFieldAiMessage.text();
//        String newFieldJsonString = newFieldText.replace("```json", "").replace("```", "");

//        MessageAssistant newFieldAssistant = AiServices.builder(MessageAssistant.class)
//                .chatLanguageModel(model)
//                .tools(bochaAPITool).build();
//
//        String newFieldJsonString = newFieldAssistant.dealNewField(baseName);
//        newFieldJsonString = newFieldJsonString.replace("```json", "").replace("```", "");
//        log.info("生成新字段返回结果:{}",newFieldJsonString);
//        AiEnterpriseEntity newFieldAiEnterpriseEntity = JSONObject.parseObject(newFieldJsonString, AiEnterpriseEntity.class);

        MessageAssistant newFieldAssistant = AiServices.builder(MessageAssistant.class)
                .chatLanguageModel(model)
                .tools(searXNGWebSearchTool).build();

        NewFieldDto newFieldDto = newFieldAssistant.dealNewFieldNew(baseName);
        AiEnterpriseEntity newFieldAiEnterpriseEntity = new AiEnterpriseEntity();
        BeanUtils.copyProperties(newFieldDto, newFieldAiEnterpriseEntity);
        log.info("生成新字段返回结果:{}",newFieldDto);

        populateValue(enterpriseEntity, newFieldAiEnterpriseEntity, aClass, true);
        enterpriseEntity.setAiDealFlag("1");
        dealBidProject(enterpriseEntity, formatter);
        aiEnterpriseService.saveOrUpdate(enterpriseEntity);
        dealProduct(enterpriseEntity, categoryMap, categoryNames);
    }



    private void dealBidProject(AiEnterpriseEntity enterpriseEntity, SimpleDateFormat formatter) {
        List<BiddingProjectEntity> biddingProjectList = biddingProjectMapper.projectList(enterpriseEntity.getBaseId());
        StringBuilder prjectBuild = new StringBuilder();
        if(!CollectionUtils.isEmpty(biddingProjectList)){
            for (int i = 0; i < biddingProjectList.size(); i++) {
                BiddingProjectEntity biddingProjectEntity = biddingProjectList.get(i);
                String projectName = biddingProjectEntity.getProjectName();
                Date publishDate = biddingProjectEntity.getPublishDate();
                String dateFormat = formatter.format(publishDate);
                prjectBuild.append(i+1).append(StrUtil.DOT).append(StrUtil.SPACE).append(projectName).append("====").append(dateFormat).append("<br>");
            }
            enterpriseEntity.setBidProjectFlag("1");
            enterpriseEntity.setBidProjectName(prjectBuild.toString());
        }else{
            enterpriseEntity.setBidProjectFlag("0");
        }
    }

    private void dealProduct(AiEnterpriseEntity enterpriseEntity, Map<String, String> categoryMap, String categoryNames) {
        List<AiProductEntity> productList = aiProductService.list(new LambdaQueryWrapper<AiProductEntity>().eq(AiProductEntity::getEnterpriseId, enterpriseEntity.getBaseId()));
        Map<String, AiProductEntity> productMap = productList.stream().collect(Collectors.toMap(m->m.getBaseName(),m->m, (existing, replacement) -> existing));
        StringBuilder sb = new StringBuilder();
        if(!StringUtils.isEmpty(enterpriseEntity.getMainProducts())){
            sb.append(enterpriseEntity.getMainProducts());
        }
        if(!CollectionUtils.isEmpty(productList)){
            String productNames = productList.stream().map(m->m.getBaseName()).collect(Collectors.joining(StrUtil.COMMA));
            if(!StringUtils.isEmpty(enterpriseEntity.getMainProducts())){
                sb.append(StrUtil.COMMA).append(productNames);
            }else{
                sb.append(productNames);
            }


        }
        String productCategoryPrompt = String.format(PromptConstant.PRODUCT_CATEGORY_PROMPT, enterpriseEntity.getBaseName(), sb.toString(), categoryNames);
        ChatMessage productChatMessage = new UserMessage(productCategoryPrompt);
        ChatResponse productChat = model.chat(productChatMessage);
        AiMessage productAiMessage = productChat.aiMessage();
        String productText = productAiMessage.text();
        String productJsonString = productText.replace("```json", "").replace("```", "");

//        MessageAssistant productAssistant = AiServices.builder(MessageAssistant.class)
//                .chatLanguageModel(model)
//                .tools(bochaAPITool).build();
//        String productJsonString = productAssistant.dealProduct(enterpriseEntity.getBaseName(),sb.toString(), categoryNames);
        log.info(productJsonString);
        log.info("生成产品返回结果:{}",productJsonString);
        List<AiProductEntity> aiProductList = JSONObject.parseArray(productJsonString, AiProductEntity.class);
        List<AiProductEntity> saveProductList = new ArrayList();
        if(!CollectionUtils.isEmpty(aiProductList)){
            for(AiProductEntity aiProductEntity : aiProductList){
                String productName = aiProductEntity.getBaseName();
                if(productMap.get(productName) != null){
                    AiProductEntity existProductEntity = productMap.get(productName);
                    existProductEntity.setCategory(categoryMap.get(aiProductEntity.getCategory()));
                    saveProductList.add(existProductEntity);
                }else{
                    AiProductEntity newProductEntity = new AiProductEntity();
                    newProductEntity.setEnterpriseId(enterpriseEntity.getBaseId());
                    newProductEntity.setBaseName(productName);
                    newProductEntity.setCategory(categoryMap.get(aiProductEntity.getCategory()));
                    saveProductList.add(newProductEntity);
                }
            }
            aiProductService.saveOrUpdateBatch(saveProductList);

        }
    }

    private static Class<? extends AiEnterpriseEntity> populateValue(AiEnterpriseEntity destEntity, AiEnterpriseEntity sourceEntity, Class<? extends AiEnterpriseEntity> destClass,boolean dealOldFieldFlag) throws IllegalAccessException, NoSuchFieldException {
        Class<?> clazz = sourceEntity.getClass();

        Class<? extends AiEnterpriseEntity> aClass = destClass == null ? destEntity.getClass() : destClass;
        // 获取对象的字段
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true); // 设置为可访问私有字段
            String fieldName = field.getName();
            Object fieldValue = field.get(sourceEntity);
            if("serialVersionUID".equals(fieldName)){
                continue;
            }
            if (fieldValue != null) {
                Field field1 = aClass.getDeclaredField(fieldName);
                field1.setAccessible(true);
                Object oldFieldValue = field1.get(destEntity);
                if(dealOldFieldFlag){
                    if(oldFieldValue == null){
                        field1.set(destEntity, fieldValue);
                    }
                }else{
                    if("mainProducts".equals(fieldName)){
                        if(oldFieldValue != null && !"".equals(oldFieldValue)){
                            field1.set(destEntity, fieldValue);
                        }
                    }else{
                        field1.set(destEntity, fieldValue);
                    }
                }

            }
        }
        return aClass;
    }

}
